package CPU.rv64_5stage

import chisel3._
import chisel3.util._
import chisel3.util.experimental.BoringUtils
import difftest._



class Core extends Module with HasInstrType {
  val io = IO(new Bundle{
    val imem = new RomIO
    val dmem = new RamIO
  })

  val fetch = Module(new InstFetch).io
  val decode = Module(new Decode).io
  val exec = Module(new Execution).io
  val memacc = Module(new MemAccess).io
  // 1.fetch
  val if2id = RegNext(fetch.if2id)
  io.imem <> fetch.imem
  fetch.isbran := decode.isbran
  fetch.branpc := decode.hitpc
  // 2.decode
  decode.if2id <> if2id
  // 3.exec
  val id2ex = RegNext(decode.id2ex)
  exec.exin <> id2ex
  // 4.memaccess
  val ex2mem = RegNext(exec.ex2mem)
  memacc.memin := ex2mem
  io.dmem <> memacc.dmem
  // 5.wb
  decode.mem2wb <> memacc.mem2wb
//  decode.mem2wb.rfwdata := memacc.mem2wb.rfwdata
//  decode.mem2wb.rfwaddr := memacc.mem2wb.rfwaddr
//  decode.mem2wb.rfwen   := memacc.mem2wb.rfwen

  printf("%x %x %x %x\n",exec.exin.pcinst.inst,exec.exin.in1, exec.exin.in2,exec.ex2mem.exout)

  ////////////////////////////////////////////
  /* ----- Difftest ------------------------------ */
//  val pc_valid = WireInit(false.B)
//  BoringUtils.addSink(pc_valid, "pc_valid")
  val dt_ic = Module(new DifftestInstrCommit)
  dt_ic.io.clock    := clock
  dt_ic.io.coreid   := 0.U
  dt_ic.io.index    := 0.U
  dt_ic.io.valid    := RegNext(memacc.mem2wb.pcinst.pc_valid)//true.B
  dt_ic.io.pc       := RegNext(memacc.mem2wb.pcinst.pc)
  dt_ic.io.instr    := RegNext(memacc.mem2wb.pcinst.inst)
  dt_ic.io.skip     := false.B
  dt_ic.io.isRVC    := false.B
  dt_ic.io.fpwen    := false.B
  dt_ic.io.rfwen    := RegNext(memacc.mem2wb.rfwen)
  dt_ic.io.wpdest   := DontCare
  dt_ic.io.wdest    := RegNext(memacc.mem2wb.rfwaddr)

  val difftest_wb = Module(new DifftestIntWriteback)
  difftest_wb.io.clock := clock
  difftest_wb.io.coreid := 0.U
  difftest_wb.io.valid := true.B
  difftest_wb.io.dest := RegNext(memacc.mem2wb.rfwaddr)
  difftest_wb.io.data := RegNext(memacc.mem2wb.rfwdata)

  val cycle_cnt = RegInit(0.U(64.W))
  val instr_cnt = RegInit(0.U(64.W))

  cycle_cnt := cycle_cnt + 1.U
  instr_cnt := instr_cnt + 1.U

  val rf_a0 = WireInit(0.U(64.W))
  BoringUtils.addSink(rf_a0, "rf_a0")

  val dt_te = Module(new DifftestTrapEvent)
  dt_te.io.clock    := clock
  dt_te.io.coreid   := 0.U
  dt_te.io.valid    := RegNext(memacc.mem2wb.pcinst.inst === "h0000006b".U)
  dt_te.io.code     := RegNext(rf_a0(2, 0))
  dt_te.io.pc       := RegNext(memacc.mem2wb.pcinst.pc)
  dt_te.io.cycleCnt := RegNext(cycle_cnt)
  dt_te.io.instrCnt := RegNext(instr_cnt)

  val dt_cs = Module(new DifftestCSRState)
  dt_cs.io.clock          := clock
  dt_cs.io.coreid         := 0.U
  dt_cs.io.priviledgeMode := 3.U  // Machine mode
  dt_cs.io.mstatus        := 0.U
  dt_cs.io.sstatus        := 0.U
  dt_cs.io.mepc           := 0.U
  dt_cs.io.sepc           := 0.U
  dt_cs.io.mtval          := 0.U
  dt_cs.io.stval          := 0.U
  dt_cs.io.mtvec          := 0.U
  dt_cs.io.stvec          := 0.U
  dt_cs.io.mcause         := 0.U
  dt_cs.io.scause         := 0.U
  dt_cs.io.satp           := 0.U
  dt_cs.io.mip            := 0.U
  dt_cs.io.mie            := 0.U
  dt_cs.io.mscratch       := 0.U
  dt_cs.io.sscratch       := 0.U
  dt_cs.io.mideleg        := 0.U
  dt_cs.io.medeleg        := 0.U

  val difftestArchEvent = Module(new DifftestArchEvent)
  difftestArchEvent.io.clock := clock
  difftestArchEvent.io.coreid := 0.U // TODO
  difftestArchEvent.io.intrNO := DontCare
  difftestArchEvent.io.cause := DontCare
  difftestArchEvent.io.exceptionPC := DontCare
  difftestArchEvent.io.exceptionInst := DontCare


}
